home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 October: Mac OS SDK / Dev.CD Oct 96 SDK / Dev.CD Oct 96 SDK2.toast / Development Kits (Disc 2) / OpenDoc Development Framework / ODFDev / ODF / Found / ODUtils / Unused / Except.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-16  |  12.9 KB  |  595 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        Except.cpp
  3.  
  4.     Contains:    Exception-handling utility
  5.  
  6.     Owned by:    Jens Alfke
  7.  
  8.     Copyright:    © 1993 - 1995 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     
  11.     In Progress:
  12.         
  13. */
  14.  
  15. #ifndef _PLATFORM_MACINTOSH_
  16. #define DONT_USE_STACKCRAWL
  17. #endif
  18.  
  19. #ifndef __EXCEPT__
  20. #include "Except.h"
  21. #endif
  22.  
  23. #ifndef _ODDEBUG_
  24. #include "ODDebug.h"
  25. #endif
  26.  
  27. #ifndef SOM_Module_OpenDoc_Errors_defined
  28. #include "ErrorDef.xh"
  29. #endif
  30.  
  31. #ifndef _PLFMDEF_
  32. #include "PlfmDef.h"
  33. #endif
  34.  
  35. #ifndef _UTILERRS_
  36. #include "UtilErrs.h"
  37. #endif
  38.  
  39. #ifndef DONT_USE_STACKCRAWL
  40. #ifndef _CRAWL_
  41. #include <Crawl.h>
  42. #endif
  43. #endif
  44.  
  45. #ifndef __SOM__
  46. #include <som.xh>
  47. #endif
  48.  
  49. #ifndef __RESOURCES__
  50. #include <Resources.h>
  51. #endif
  52.  
  53. #ifndef __STRINGS__
  54. #include <Strings.h>
  55. #endif
  56.  
  57. #ifndef _ODMEMORY_
  58. #include "ODMemory.h"
  59. #endif
  60.  
  61. #include <stdio.h>
  62. #include <stdarg.h>
  63. #include <string.h>
  64.  
  65.  
  66. extern void BREAK( const char[] );
  67.  
  68.  
  69. static ODBoolean gBreakOnThrow = kODFalse;    // Set to true to break on exceptions
  70.  
  71.  
  72. const ODSize kSpareMemSize = 512;
  73.  
  74. static void* gSpareMem = kODNULL;
  75. // gSpareMem is a block of memory we keep around to make sure that in an emergency
  76. // we always have enough memory to allocate a SOM exception, by releasing the spare
  77. // block if we have to.
  78.  
  79.  
  80. #pragma segment ODExceptions
  81.  
  82.  
  83. //=====================================================================================
  84. // Setting BreakOnThrow
  85. //=====================================================================================
  86.  
  87.  
  88. ODBoolean
  89. BreakOnThrow( ODBoolean brk )
  90. {
  91.     ODBoolean oldBrk = gBreakOnThrow;
  92.     gBreakOnThrow = brk;
  93.     return oldBrk;
  94. }
  95.  
  96.  
  97. //=====================================================================================
  98. // Initializing ODException Structures
  99. //=====================================================================================
  100.  
  101.  
  102. static void
  103. InitODException( ODException *x, ODError error, const char *message, ODSLong msgsize )
  104. {
  105.     x->error = error;
  106.     if( message ) {
  107.         ODBlockMove(message,x->message,msgsize);
  108.         x->message[msgsize-1] = '\0';
  109.     } else
  110.         x->message[0] = 0;
  111. }
  112.  
  113.  
  114. static ODException*
  115. NewODException( ODError error, const char *message )
  116. {
  117.     SOMFree(gSpareMem);                            // Get some slack
  118.     
  119.     ODULong size = message ?(strlen(message)+1) :1;
  120.     if( size>256 ) size=256;
  121.     ODException *x = (ODException*) SOMMalloc( sizeof(ODError) + size );
  122.     
  123.     if( x )
  124.         InitODException(x,error,message,size);
  125.     
  126.     gSpareMem = SOMMalloc(kSpareMemSize);        // Tighten up again
  127.     
  128.     return x;
  129. }
  130.  
  131.  
  132. #ifndef _NATIVE_EXCEPTIONS_
  133.  
  134. //=====================================================================================
  135. // Stack Maintenance
  136. //=====================================================================================
  137.  
  138.  
  139. static ODExceptionFrame *gTopHandler = kODNULL;
  140.  
  141. inline ODExceptionFrame* GetTopHandler( )
  142. { return gTopHandler; }
  143.  
  144.  
  145. //=====================================================================================
  146. // ODExceptionFrame
  147. //=====================================================================================
  148.  
  149.  
  150. #define kAlreadyPoppedHandler ((ODExceptionFrame*)0xDEADBEEF)
  151.  
  152.  
  153. #ifndef _ASM_XTRY_
  154. jmp_buf* _xTryEv( ODExceptionFrame *x, Environment *ev )
  155. {
  156.     if( ! gSpareMem )
  157.         gSpareMem = SOMMalloc(kSpareMemSize);
  158.         
  159.     x->fError = kODNoError;
  160.     x->fODException = kODNULL;
  161.     x->fEv = ev;
  162.     x->fDestructoList = kODNULL;
  163.     x->fPrev = GetTopHandler();
  164.     gTopHandler = x;
  165.     return &x->fBuffer;
  166. }
  167.  
  168. jmp_buf* _xTry( ODExceptionFrame *x )
  169. {
  170.     if( ! gSpareMem )
  171.         gSpareMem = SOMMalloc(kSpareMemSize);
  172.         
  173.     x->fError = kODNoError;
  174.     x->fODException = kODNULL;
  175.     x->fEv = kODNULL;
  176.     x->fDestructoList = kODNULL;
  177.     x->fPrev = GetTopHandler();
  178.     gTopHandler = x;
  179.     return &x->fBuffer;
  180. }
  181. #endif /*_ASM_XTRY_*/
  182.  
  183.  
  184. void _xPop( ODExceptionFrame *x )
  185. {
  186.     if( GetTopHandler() == x )
  187.         // Remove myself from the stack if (a) I'm at ENDTRY and no exception was thrown,
  188.         // or (b) someone exited (probably via 'return') from within the TRY block:
  189.         gTopHandler = x->fPrev;
  190.         
  191.     else {
  192.         if( x->fPrev == kAlreadyPoppedHandler )
  193.             // Do nothing if I was already popped by a THROW.
  194.             ;
  195.         else {
  196.             /*  At this point the astute reader will be wondering how a non-top
  197.                 exception handler could be destructed first. Given correct inside-
  198.                 out destruction of stack-based objects, this should never happen;
  199.                 however, some compilers will mix up the order in certain cases.
  200.                 Therefore we roll up our sleeves and prepare to destruct any
  201.                 intervening handlers on the stack: */
  202.                 
  203.             WARN("Destructing non-top excpt frame %p",x);
  204.             
  205.             ODExceptionFrame *e;
  206.             for( e=gTopHandler; e && e->fPrev!=x; e=e->fPrev )
  207.                 ;
  208.             if( e==kODNULL )
  209.                 WARN("Excpt frame %p not found on stack!",x);
  210.             else
  211.                 e->fPrev = x->fPrev;
  212.         }
  213.         
  214.         /*    If exiting a SOM_TRY handler with an error, store it in the Environment: */
  215.         if( x->fEv ) {
  216.             if( x->fODException ) {
  217.                 somSetException(x->fEv,USER_EXCEPTION,ex_ODException,x->fODException);
  218.                 x->fODException = kODNULL;
  219.             } else if( x->fError )
  220.                 ODSetSOMException(x->fEv,x->fError);
  221.         }
  222.     }
  223.     
  224.     if( x->fODException ) {
  225.         SOMFree(x->fODException);
  226.         if( ! gSpareMem )
  227.             gSpareMem = SOMMalloc(kSpareMemSize);
  228.     }
  229. }
  230.  
  231.  
  232. void
  233. ODExceptionFrame::Throw( ODError err, const char* msg, ODException *x )
  234. {
  235.     if( err == kODNoError ) {
  236.         WARN("Do not call THROW(0)!");
  237.         return;
  238.     }
  239.         
  240.     WASSERT(this==GetTopHandler());
  241.  
  242.     // Call the destructor of each of my destructos:
  243.     for( Destructo *d=fDestructoList; d; d=d->EmergencyDestruct() )
  244.         ;
  245.     
  246.     gTopHandler = fPrev;                // Pop the exception handler
  247.     fPrev = kAlreadyPoppedHandler;
  248.     
  249.     // Store error info in this handler. If there's a message, need to copy
  250.     // it into an ODException structure if possible:
  251.     fError = err;
  252.     if( x )
  253.         fODException = x;
  254.     else if( msg && msg[0]!='\0' )
  255.         fODException = NewODException(err,msg);
  256.     else
  257.         fODException = kODNULL;
  258.     
  259.     longjmp(fBuffer,1);                    // SHAZAM!
  260. }
  261.  
  262.  
  263. void
  264. _xReraise( ODExceptionFrame *xf )
  265. {
  266. #if ODDebug
  267.     if( GetTopHandler()==xf )
  268.         BREAK("Reraise called on active exception handler!");
  269.     // Not fatal but probably a mistaken usage of RERAISE.
  270. #endif
  271.  
  272.     if( xf->fEv ) {
  273.         WARN("RERAISE in SOM_CATCH_ALL block is illegal");
  274.         return;
  275.     }
  276.     
  277.     WASSERTM(xf->fError!=kODNoError,"RERAISE called with no exception");
  278.     
  279.     // Throw the exception, re-using the ODException if possible:
  280.     if( GetTopHandler() ==kODNULL )
  281.         BREAK("No handler to CATCH exception!!");
  282.     else {
  283.         ODException *x = xf->fODException;
  284.         xf->fODException = kODNULL;
  285.         GetTopHandler()->Throw(xf->fError,kODNULL,x);
  286.     }
  287. }
  288.  
  289.  
  290. void
  291. _xSetErrorCode( ODExceptionFrame *xf, ODError err )
  292. {
  293.     xf->fError = err;
  294.     if( err ) {
  295.         if( xf->fODException )
  296.             xf->fODException->error = err;
  297.     } else {
  298.         SOMFree(xf->fODException);
  299.         xf->fODException = kODNULL;
  300.     }
  301. }
  302.  
  303.  
  304. void
  305. _xSetErrorMessage( ODExceptionFrame *xf, const char *message )
  306. {
  307.     if( message && message[0]!='\0' ) {
  308.         ODException *x = NewODException(xf->fError,message);
  309.         if( x ) {
  310.             SOMFree(xf->fODException);
  311.             xf->fODException = x;
  312.         }
  313.     } else {
  314.         SOMFree(xf->fODException);
  315.         xf->fODException = kODNULL;
  316.     }
  317. }
  318.  
  319.  
  320. //=================================================================================== 
  321. // Destructo class
  322. //=================================================================================== 
  323.  
  324.  
  325. #define kIWuzDestructed ((Destructo*)0xDEADBEEF)
  326. #define kEmergencyDestructing    ((Destructo*)0xFADEBABE)
  327.  
  328.  
  329. Destructo::Destructo( )
  330. {
  331.     /* Constructor adds me to the current exception frame's destructo list. */
  332.     if( GetTopHandler() ) {
  333.         fPrevDestructo = gTopHandler->fDestructoList;
  334.         gTopHandler->fDestructoList = this;
  335.     } else
  336.         fPrevDestructo = kODNULL;
  337. }
  338.  
  339.  
  340. Destructo::~Destructo( )
  341. {
  342.     /*    Destructor removes me from the owner's destructo list, except during
  343.         an emergency destruct while an exception is being thrown; in that case
  344.         the exception handler takes care of that bit itself. */
  345.         
  346.     if( fPrevDestructo != kEmergencyDestructing ) {
  347. #if ODDebug
  348.     if( fPrevDestructo==kIWuzDestructed ) {
  349.         WARN("Destructo %p being destructed twice!",this);
  350.         return;
  351.     }
  352. #endif
  353.     if( GetTopHandler() ) {
  354.         if( gTopHandler->fDestructoList == this )
  355.             gTopHandler->fDestructoList = fPrevDestructo;
  356.         else
  357.             WARN("Destructo %p being destructed is not top of list",this);
  358.     }
  359.     }
  360.     
  361. #if ODDebug
  362.     fPrevDestructo = kIWuzDestructed;
  363. #endif
  364. }
  365.  
  366.  
  367. Destructo*
  368. Destructo::EmergencyDestruct( )
  369. {
  370.     /*    My owner is _not_ the top handler right now, because it's destructing me in
  371.         a nested TRY block. Jam a special marker into fPrevDestructo to tell my
  372.         destructor not to mess with the Destructo chain; then return the next
  373.         destructo in the chain to help the handler walk it. */
  374.     
  375.     Destructo *prev = fPrevDestructo;
  376. #if ODDebug
  377.     if( prev==kIWuzDestructed ) {
  378.         WARN("Destructo %p being emergency-destructed twice!",this);
  379.         return kODNULL;
  380.     }
  381. #endif
  382.  
  383.     fPrevDestructo = kEmergencyDestructing;
  384.     TRY{
  385.         this->~Destructo();
  386.     }CATCH_ALL{
  387.         // Ignore the nested exception.
  388.     }ENDTRY
  389.     return prev;
  390. }
  391.  
  392.  
  393. #endif /*not _NATIVE_EXCEPTIONS_*/
  394.  
  395.  
  396. //=================================================================================== 
  397. // THROW, et al
  398. //=================================================================================== 
  399.  
  400.  
  401. static void
  402. DoThrow( ODError err, const char* msg, ODException *x = kODNULL )
  403. {
  404.     if( err == kODNoError ) {
  405.         WARN("Do not call THROW(0)!");
  406.         return;
  407.     }
  408.             
  409. #if ODDebug
  410.     // Dump useful into to stdout or MacsBug. Ignore AE coercion-failure error
  411.     // (-1700 == errAECoercionFail) since it happens as part of normal operation.
  412.     
  413.     if( (GetOutputMode() != kNoOutput || gBreakOnThrow)
  414.                 && err!=-1700 && err!=-1708 ) {                // Skip noise AE errors
  415.         char caller[256];
  416.         #ifndef DONT_USE_STACKCRAWL
  417.             if( ! ODHaveFreeSpace(1024,1024) )
  418.                 strcpy(caller,"??(low mem)??");
  419.             else {
  420.                 StackCrawl *sc = StackCrawl::New(2,2);
  421.                 sc->GetFrameName(0,caller);
  422.                 delete sc;
  423.             }
  424.         
  425.             if( GetOutputMode() != kNoOutput ) {
  426.                 if( msg )
  427.                     somPrintf("** THROW(%d) called by %s\n", err,caller);
  428.                 else
  429.                     somPrintf("** THROW(%d,%s) called by %s\n", err,msg,caller);
  430.                 if( ODHaveFreeSpace(1024,1024) ) {
  431.                     StackCrawl *s = StackCrawl::New(2,-5);
  432.                     if( s ) {
  433.                         for( long i=0; i<s->CountFrames(); i++ ) {
  434.                             char name[256];
  435.                             s->GetFrameName(i,name);
  436.                             somPrintf("        %s\n",name);
  437.                         }
  438.                         delete s;
  439.                     }
  440.                 }
  441.             }
  442.         #else
  443.             strcpy(caller,"????");
  444.         #endif
  445.         
  446.         if( gBreakOnThrow )
  447.             if( msg )
  448.                 WARN("THROW(%ld,%s) called by %s", err,msg,caller);
  449.             else
  450.                 WARN("THROW(%ld) called by %s", err,caller);
  451.     }
  452. #endif
  453.  
  454. #ifdef _NATIVE_EXCEPTIONS_
  455.     ODException x;
  456.     InitODException(&x, err,msg,256);
  457.     throw(x);
  458. #else
  459.     if( GetTopHandler() ==kODNULL )
  460.         BREAK("No handler to CATCH exception!!");
  461.     else
  462.         GetTopHandler()->Throw(err,msg,x);
  463. #endif
  464. }
  465.  
  466.  
  467.  
  468. void
  469. THROW( ODError err )
  470. {
  471.     DoThrow(err,kODNULL);
  472. }
  473.  
  474.  
  475. void
  476. THROW_IF_ERROR( ODError err )
  477. {
  478.     if( err != 0 )
  479.         DoThrow(err,kODNULL);
  480. }
  481.  
  482.  
  483. void
  484. THROW_IF_NULL( void* value )
  485. {
  486.     if( value == kODNULL )
  487.         DoThrow(kODErrOutOfMemory,kODNULL);
  488. }
  489.  
  490.  
  491. #if ODDebug
  492. void
  493. THROW_IF_ERROR_M( ODError err, const char *msg )
  494. {
  495.     if( err != 0 )
  496.         DoThrow(err,msg);
  497. }
  498.  
  499. void
  500. THROW_M( ODError err, const char* msg )
  501. {
  502.     DoThrow(err,msg);
  503. }
  504.  
  505. void
  506. THROW_IF_NULL_M( void* value, const char* msg )
  507. {
  508.     if( value == kODNULL )
  509.         DoThrow(kODErrOutOfMemory,msg);
  510. }
  511. #endif /*ODDebug*/
  512.  
  513.  
  514. //=================================================================================== 
  515. // SOM EXCEPTIONS
  516. //===================================================================================
  517.  
  518.  
  519. void
  520. ODSetSOMException( Environment *ev, ODError error, const char *message /*=NULL*/ )
  521. {
  522.     if( error ) {
  523.         ODException *x = NewODException(error,message);
  524.             SOMFree(gSpareMem);                            // Get some slack
  525.             somSetException(ev,USER_EXCEPTION,ex_ODException,x);
  526.             gSpareMem = SOMMalloc(kSpareMemSize);        // Tighten up
  527.     } else {
  528.         somExceptionFree(ev);
  529.         ev->_major = NO_EXCEPTION;
  530.     }
  531. }
  532.  
  533.  
  534. #ifdef _NATIVE_EXCEPTIONS_
  535. void
  536. ODSetSOMException( Environment *ev, ODException &except )
  537. {
  538.     ODSetSOMException(ev,except.error,except.message);
  539. }
  540.  
  541. #else
  542.  
  543. void
  544. _xSetSOMException( Environment *ev, ODExceptionFrame *x )
  545. {
  546.     if( !x->fEv ) {                        // Ignore this in a SOM_TRY block
  547.         if( x->fODException ) {
  548.             SOMFree(gSpareMem);                            // Get some slack
  549.             somSetException(x->fEv,USER_EXCEPTION,ex_ODException,x->fODException);
  550.             gSpareMem = SOMMalloc(kSpareMemSize);        // Tighten up
  551.             x->fODException = kODNULL;
  552.         } else if( x->fError )
  553.             ODSetSOMException(x->fEv,x->fError);
  554.     }
  555. }
  556.  
  557. #endif
  558.  
  559.  
  560. ODError
  561. ODGetSOMException( Environment *ev )
  562. {
  563.     if( ev->_major ) {
  564.         const char *excpName = somExceptionId(ev);
  565.         if( strcmp(excpName,ex_ODException) == 0 ) {
  566.             ODException *x = (ODException*)somExceptionValue(ev);
  567.             return x->error;
  568.         } else {
  569.             WARN("Env has non-OpenDoc err: %s",excpName);
  570.             return kODErrSOMException;
  571.         }
  572.     } else
  573.         return kODNoError;
  574. }
  575.  
  576.  
  577. void
  578. CHECK_ENV( Environment *ev )
  579. {
  580.     if( ev->_major ) {
  581.         const char *excpName = somExceptionId(ev);
  582.         if( strcmp(excpName,ex_ODException) == 0 ) {
  583.             ODException x = *(ODException*)somExceptionValue(ev);
  584.             somExceptionFree(ev);
  585.             ev->_major = NO_EXCEPTION;
  586.             DoThrow(x.error, x.message);
  587.         } else {
  588.             WARN("Env has non-OpenDoc err: %s",excpName);
  589.             somExceptionFree(ev);
  590.             ev->_major = NO_EXCEPTION;
  591.             DoThrow(kODErrSOMException,kODNULL);
  592.         }
  593.     }
  594. }
  595.